//  EpsilonDominanceComparator.java
//
//  Author:
//       Antonio J. Nebro <antonio@lcc.uma.es>
//       Juan J. Durillo <durillo@lcc.uma.es>
//
//  Copyright (c) 2011 Antonio J. Nebro, Juan J. Durillo
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

package hidra.many.metaheuristics.approaches.versions.util;


import hidra.jmetal.core.Solution;

import java.util.Comparator;

import jmetal.util.comparators.OverallConstraintViolationComparator;


/**
 * This class implements a <code>Comparator</code> (a method for comparing
 * <code>Solution</code> objects) based on epsilon dominance.
 */
public class EpsilonDominanceComparator implements Comparator{
   
  /**
   * Stores the value of eta, needed for epsilon-dominance.
   */
  private double eta_;
  
  /** 
   * stores a comparator for check the OverallConstraintComparator
   */
  private static final Comparator overallConstraintViolationComparator_ =
                              new OverallConstraintViolationComparator();
  
  private double[] gmax_;
  
  /**
   * Constructor.
  *  @param eta Value for epsilon-dominance.
  */
  public EpsilonDominanceComparator(double eta, double[] gmax) {
	  this.eta_ = eta;
	  this.gmax_ = gmax;
  }
  
 /** 
  * Compares two solutions.
  * @param solution1 Object representing the first <code>Solution</code>.
  * @param solution2 Object representing the second <code>Solution</code>.
  * @return -1, or 0, or 1 if solution1 dominates solution2, both are 
  * non-dominated, or solution1 is dominated by solution2, respectively.
  */
  public int compare(Object object1, Object object2) {
    if (object1==null)
      return 1;
    else if (object2 == null)
      return -1;    
        
    Solution solution1 = (Solution)object1;
    Solution solution2 = (Solution)object2;
    
    boolean dominate1 = false;
	boolean dominate2 = false;

	for (int i = 0; i < solution1.numberOfObjectives(); i++) {
		double epsilon = eta_;

		long  index1 = (int)Math.floor((solution1.getObjective(i)/gmax_[i]) / epsilon);
		long  index2 = (int)Math.floor((solution2.getObjective(i)/gmax_[i]) / epsilon);

		if (index1 < index2) {
			dominate1 = true;

			if (dominate2) {
				return 0;
			}
		} else if (index1 > index2) {
			dominate2 = true;

			if (dominate1) {
				return 0;
			}
		}
	}

	if (!dominate1 && !dominate2) {
		
		double dist1 = 0.0;
		double dist2 = 0.0;

		for (int i = 0; i < solution1.numberOfObjectives(); i++) {
			double epsilon = eta_;

			int index1 = (int)Math.floor(solution1.getObjective(i)
					/ epsilon);
			int index2 = (int)Math.floor(solution2.getObjective(i)
					/ epsilon);

			dist1 += Math.pow(solution1.getObjective(i) - index1 * epsilon,
					2.0);
			dist2 += Math.pow(solution2.getObjective(i) - index2 * epsilon,
					2.0);
		}

		dist1 = Math.sqrt(dist1);
		dist2 = Math.sqrt(dist2);

		if (dist1 < dist2) {
			return -1;
		} else {
			return 1;
		}
	} else if (dominate1) {
		return -1;
	} else {
		return 1;
	}

    
    
   } // compare
  
  
} // EpsilonDominanceComparator
